package AICore;

import java.util.LinkedList;

import carddeck.Card;
import carddeck.Rank;
import carddeck.Suit;

public class WinningPattern {
	public enum PatternAction {
		PA_DEMAND(0),
		PA_COLORCH(1),
		PA_KINGSPADES(2),
		PA_DEFAULT(3);
		
		private final int value;
	    private PatternAction(int value) {
	        this.value = value;
	    }

	    public int getValue() {
	        return value;
	    }
	}
	private LinkedList<Card> parameter;
	private LinkedList<Card> solution;
	private PatternAction action;
	private LinkedList<Card> other;
	private double score;
	
	public double getScore() {
		return score;
	}

	public void setScore(double score) {
		this.score = score;
	}

	public LinkedList<Card> getParameter() {
		return parameter;
	}

	public void setParameter(LinkedList<Card> parameter) {
		this.parameter = parameter;
	}

	public LinkedList<Card> getSolution() {
		return solution;
	}

	public void setSolution(LinkedList<Card> solution) {
		this.solution = solution;
	}

	public PatternAction getAction() {
		return action;
	}

	public void setAction(PatternAction action) {
		this.action = action;
	}

	public LinkedList<Card> getOther() {
		return other;
	}

	public void setOther(LinkedList<Card> other) {
		this.other = other;
	}

	public WinningPattern(LinkedList<Card> solution, PatternAction action, LinkedList<Card> parameter, LinkedList<Card> other) {
		this.solution = solution;
		this.action = action;
		this.parameter = parameter;
		this.other = other;
		score=0.0;
	}
	
	@Override
	public String toString() {
		String result = "";
		if(other!=null) {
			result+="First play:";
			for(Card theCard: other)
				result+= " " +theCard.cardToString();
			result+=", to get rid of unwanted cards. After that ";
		}
		switch(action) {
		case PA_KINGSPADES:
			if(other==null)
				result+="Attack with:";
			else
				result+="attack with:";
			for(Card theCard: solution)
				result+= " " +theCard.cardToString();
			result+=", then continue with:";
			for(Card theCard: parameter)
				result+= " " +theCard.cardToString();
			result+=".";
			break;
		case PA_COLORCH:
			if(other==null)
				result+="Change color with:";
			else
				result+="change color with:";
			for(Card theCard: solution)
				result+= " " +theCard.cardToString();
			result+=", then continue with:";
			for(Card theCard: parameter)
				result+= " " +theCard.cardToString();
			result+=".";
			break;
		case PA_DEMAND:
			if(other==null)
				result+="Play:";
			else
				result+="play:";
			for(Card theCard: solution)
				result+= " " +theCard.cardToString();
			result+=" and demand " + Rank.rankToString(parameter.getFirst().getCardRank().getValue()) + ", then continue with:";
			for(Card theCard: parameter)
				result+= " " +theCard.cardToString();
			result+=".";
			break;
		case PA_DEFAULT:
			if(other==null)
				result+="Play:";
			else
				result+="play:";
			for(Card theCard: solution)
				result+= " " +theCard.cardToString();
			result+=" and win.";
			break;
		}
		return result;
	}
	
	public boolean bIsPlayable(Card onCard, boolean attacked, boolean fourAttacked, Rank demanded, Card startWith) {
		if(other==null) {
			if(startWith!=null)
				if(!solution.contains(startWith))
					return false;
			switch(action) {
			case PA_KINGSPADES:
				Card kingOfSpades=null;
				Card firstCard = null;
				
				if(startWith!=null) {
					firstCard = startWith;
					if(!bCanPlayOn(firstCard, onCard, attacked, fourAttacked, demanded))
						return false;
					for(Card theCard: solution)
						if(theCard.getCardSuit()==Suit.SPADES&&theCard!=startWith)
							return true;
					return false;
				}
				for(Card theCard: solution)
					if(attacked&&theCard.getCardSuit()!=Suit.SPADES&&theCard.getCardSuit()!=Suit.HEARTS)
						return false;
				for(Card theCard: solution)
					if(theCard.getCardSuit()==Suit.SPADES) {
						kingOfSpades=theCard;
						break;
					}
				for(Card theCard: solution)
					if(bCanPlayOn(theCard, onCard, attacked, fourAttacked, demanded)&&theCard!=kingOfSpades) {
						return true;
				}
				return false;
			case PA_DEMAND:
			case PA_COLORCH:
			case PA_DEFAULT:
			default:
				if(startWith==null)
					for(Card theCard: solution) {
						if(bCanPlayOn(theCard, onCard, attacked, fourAttacked, demanded))
							return true;
					}
				else
					if(bCanPlayOn(startWith, onCard, attacked, fourAttacked, demanded))
						return true;
				return false;
			}
		}
		else {
			if(startWith!=null)
				if(!other.contains(startWith))
					return false;
			if(startWith==null)
				for(Card theCard: other) {
					if(bCanPlayOn(theCard, onCard, attacked, fourAttacked, demanded))
						return true;
				}
			else
				if(bCanPlayOn(startWith, onCard, attacked, fourAttacked, demanded))
					return true;
			return false;
		}
	}
	
	public static boolean bCanPlayOn(Card tryCard, Card onCard, boolean attacked, boolean fourAttacked, Rank demanded) {
		if(onCard.getFakeCard()!=null) {
			onCard=onCard.getFakeCard();
			if(onCard.getFakeCard()!=null)
				onCard=onCard.getFakeCard();
		}
		return bCardsMatch(onCard, tryCard, demanded)&&bCanBePlayed(tryCard, true, attacked, fourAttacked);
	}
	
	private static boolean bCanBePlayed(Card theCard, boolean bFirst, boolean attacked, boolean fourAttacked) {
		if (attacked)
			if (theCard.getCardRank() == Rank.TWO
					|| theCard.getCardRank() == Rank.THREE
					|| theCard.getCardRank() == Rank.KING
					&& (theCard.getCardSuit() == Suit.HEARTS || theCard
							.getCardSuit() == Suit.SPADES)
					|| theCard.getCardRank() == Rank.QUEEN
					&& theCard.getCardSuit() == Suit.SPADES
					|| theCard.getCardRank() == Rank.QUEEN
					&& !bFirst)
				return true;
			else
				return false;
		else if (fourAttacked)
			if (theCard.getCardRank() == Rank.FOUR
					|| theCard.getCardRank() == Rank.QUEEN
					&& theCard.getCardSuit() == Suit.SPADES
					|| theCard.getCardRank() == Rank.QUEEN
					&& !bFirst)
				return true;
			else
				return false;
		else
			return true;
	}
	
	private static boolean bCardsMatch(Card card1, Card card2, Rank demanded) {
		if (card1 == null || card2 == null)
			System.out.println("null w bCardsMatch!");
		if (demanded != null)
			if (demanded != card2.getCardRank()
					&& card2.getCardRank() != Rank.JACK
					&& card2.getCardRank() != Rank.QUEEN)
				return false;
			else if (card2.getCardRank() == Rank.JACK && card1.getCardSuit() != card2.getCardSuit()&& card1.getCardRank()!=Rank.QUEEN&&card1.getCardRank()!=Rank.JACK)
				return false;
			else
				return true;
		else if (card1.getCardSuit() == card2.getCardSuit())
			return true;
		else if (card1.getCardRank() == card2.getCardRank())
			return true;
		else if (card1.getCardRank() == Rank.QUEEN
				|| card2.getCardRank() == Rank.QUEEN)
			return true;
		else
			return false;
	}
}
